#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>

#include "uvlog.h"
#include "config.h"
#include "file_manager.h"

using namespace std;
void usage(int argc,char** argv);
void headDump(int);
void segDump(int,int);

int main(int argc,char** argv)
{
	usage(argc,argv);

	const char *cfgfile = argv[1];
	if(access(cfgfile,F_OK))
	{
		cout << "config file not reachable!" << endl;
		exit(1);
	}

	CConfig * cfg = CConfig::getInstance();
	if(cfg->ParseConfig(cfgfile) != 0){
		cerr << "parse config failed";
		return -1;
	}
	
	//INIT_LOG("/dev/null",1024*1024,5);
	bool bfirst = false;
	if(access("/tmp/file_watch.log",F_OK))
	{
		bfirst = true;	
	}
	INIT_LOG("/tmp/file_watch.log",1024*1024,5);
	g_pLog->setLogLevel(0);

	if(bfirst)
	{
		chmod("/tmp/file_watch.log",777);
	}

	
	string df = cfg->GetStrVal("BTREE","path");
	df += "/";
	df += cfg->GetStrVal("BTREE","prefix");
	df += ".idx.0";

	
	if(access(df.c_str(),F_OK|R_OK) < 0){
		cout<< df.c_str()<<endl;
		cerr << "access file " << argv[1] << " failed,errno = " <<errno<<strerror(errno)<< endl;
		return -1;
	}
	
	int fd = open(df.c_str(),O_RDONLY);
	if(fd < 0){
		cerr << "open file failed" << endl;
		return -1;
	}
	
	if(strcmp(argv[2],"head") == 0){
		headDump(fd);
		close(fd);
		return 0;
	}
	
	if(strcmp(argv[2],"seg") == 0){
		char prefix[1024];
		strcpy(prefix,argv[1]);
		for(int i = strlen(argv[1]),j=0; i > 0 ; --i){
			if(prefix[i] == '.') ++j;
			if(j == 1){
				*(prefix+i) = 0;
				break;
			}
		}
		
		uint64_t orgOffset = (uint64_t)atoll(argv[3]);
		unsigned int fseq = orgOffset / PER_FILE_SIZE;
		unsigned int offset = orgOffset % PER_FILE_SIZE;
		
		if(fseq != 0){
			close(fd);
			
			sprintf(prefix+strlen(prefix),".%d",fseq);
			fd = open(prefix,O_RDONLY);
			if(fd < 0){
				cerr << "open file " << prefix << " failed" << endl;
				return -1;
			}
		}
		
		if(offset <= 0 || offset > PER_FILE_SIZE){
			cerr << "illegal segno" << endl;
			return -1;
		}
		
		segDump(fd,offset);
		
		close(fd);
		return 0;
	}
	
	return 0;
}

void usage(int argc,char** argv)
{
	if(argc < 3 || argc > 4
		|| (argc == 3 && strcmp(argv[2],"head") != 0) 
		|| (argc == 4 && strcmp(argv[2],"seg") != 0))
	{
		cout << "usage:" << endl
				<< argv[0] << " filename head" << endl
				<< argv[0] << " filename seg segno" << endl;
		
		exit(1);
	}
}

#define MMAP(fd,offset) mmap(NULL,PER_PAGE_SIZE,PROT_READ,MAP_SHARED,fd,offset)
void headDump(int fd)
{
	void* addr = MMAP(fd,0);
	if(addr == MAP_FAILED){
		cerr << "map failed:" << strerror(errno) << endl;
		return;
	}
	
	IndexFileHeader idxHeader(addr);
	
	cout << idxHeader.dump();
}

void segDump(int fd,int offset)
{
	//cout << "offset=" << offset << endl;
	
	void* addr = MMAP(fd,offset);
	if(addr == MAP_FAILED){
		cerr << "map failed:" << strerror(errno) << endl;
		return;
	}
	
	IndexFilePage idxPage(addr);
	cout << idxPage.dump(CConfig::getInstance()->GetStrVal("BTREE","key")) ;
}
